﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Net;
using System.Web;

namespace Obsidian.Web
{

    /// <summary>
    /// HttpWeb请求类
    /// Author:郑金泉
    /// Created:2010-09-01
    /// </summary>
    public sealed class HttpRequestor
    {
        //默认请求超时时间
        private static int defaultTimeOut = -1;

        /// <summary>
        /// 默认请求超时时间
        /// </summary>
        public static int DefaultTimeOut
        {
            get { return defaultTimeOut; }
            set { defaultTimeOut = value; }
        }

        #region Get方式

        /// <summary>
        /// HttpWebGet方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <returns></returns>
        public static string Get(string url)
        {
            string status;
            return WebRequest(RequestMethod.Get, url, false, null, null, -1, out status);
        }

        /// <summary>
        /// HttpWebGet方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static string Get(string url, int timeout)
        {
            string status;
            return WebRequest(RequestMethod.Get, url, false, null, null, timeout, out status);
        }

        /// <summary>
        /// HttpWebGet方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <returns></returns>
        public static string Get(string url, Hashtable htParams)
        {
            string status;
            return WebRequest(RequestMethod.Get, url, false, htParams, null, -1, out status);
        }

        /// <summary>
        /// HttpWebGet方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static string Get(string url, Hashtable htParams, int timeout)
        {
            string status;
            return WebRequest(RequestMethod.Get, url, false, htParams, null, timeout, out status);
        }

        #endregion

        #region GetStream

        /// <summary>
        /// HttpWebGet方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <returns></returns>
        public static Stream GetStream(string url)
        {
            string status;
            return WebRequestStream(RequestMethod.Get, url, false, null, null, -1, out status);
        }

        /// <summary>
        /// HttpWebGet方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static Stream GetStream(string url, int timeout)
        {
            string status;
            return WebRequestStream(RequestMethod.Get, url, false, null, null, timeout, out status);
        }

        /// <summary>
        /// HttpWebGet方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <returns></returns>
        public static Stream GetStream(string url, Hashtable htParams)
        {
            string status;
            return WebRequestStream(RequestMethod.Get, url, false, htParams, null, -1, out status);
        }

        /// <summary>
        /// HttpWebGet方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static Stream GetStream(string url, Hashtable htParams, int timeout)
        {
            string status;
            return WebRequestStream(RequestMethod.Get, url, false, htParams, null, timeout, out status);
        }

        #endregion

        #region Post方式

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <returns></returns>
        public static string Post(string url)
        {
            string status;
            return WebRequest(RequestMethod.Post, url, false, null, null, -1, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <returns></returns>
        public static string Post(string url, out string status)
        {
            return WebRequest(RequestMethod.Post, url, false, null, null, -1, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static string Post(string url, int timeout)
        {
            string status;
            return WebRequest(RequestMethod.Post, url, false, null, null, timeout, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <returns></returns>
        public static string Post(string url, Hashtable htParams, out string status)
        {
            return WebRequest(RequestMethod.Post, url, false, htParams, null, -1, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <returns></returns>
        public static string Post(string url, Hashtable htParams)
        {
            string status;
            return WebRequest(RequestMethod.Post, url, false, htParams, null, -1, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static string Post(string url, Hashtable htParams, int timeout)
        {
            string status;
            return WebRequest(RequestMethod.Post, url, false, htParams, null, timeout, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="postData">发送的数据</param>
        /// <returns></returns>
        public static string Post(string url, string postData)
        {
            string status;
            return WebRequest(RequestMethod.Post, url, false, null, postData, -1, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="postData">发送的数据</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static string Post(string url, string postData, int timeout)
        {
            string status;
            return WebRequest(RequestMethod.Post, url, false, null, postData, timeout, out status);
        }

        #endregion

        #region PostStream

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <returns></returns>
        public static Stream PostStream(string url)
        {
            string status;
            return WebRequestStream(RequestMethod.Post, url, false, null, null, -1, out status);
        }
        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static Stream PostStream(string url, int timeout)
        {
            string status;
            return WebRequestStream(RequestMethod.Post, url, false, null, null, timeout, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <returns></returns>
        public static Stream PostStream(string url, Hashtable htParams)
        {
            string status;
            return WebRequestStream(RequestMethod.Post, url, false, htParams, null, -1, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="htParams">参数</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static Stream PostStream(string url, Hashtable htParams, int timeout)
        {
            string status;
            return WebRequestStream(RequestMethod.Post, url, false, htParams, null, timeout, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="postData">发送的数据</param>
        /// <returns></returns>
        public static Stream PostStream(string url, string postData)
        {
            string status;
            return WebRequestStream(RequestMethod.Post, url, false, null, postData, -1, out status);
        }

        /// <summary>
        /// HttpWebPost方式请求
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="postData">发送的数据</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static Stream PostStream(string url, string postData, int timeout)
        {
            string status;
            return WebRequestStream(RequestMethod.Post, url, false, null, postData, timeout, out status);
        }

        #endregion

        #region SOAP

        /// <summary>
        /// HttpWeb请求(SOAP1.2协议)
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="method">方法名</param>
        /// <param name="htParams">参数</param>
        /// <returns></returns>
        public static string PostBySoap(string url, string xmlns, string method, Hashtable htParams)
        {
            string postData = CreateSoapRequestXml(method, xmlns, htParams);
            string status;
            return WebRequest(RequestMethod.Post, url, true, null, postData, -1, out status);
        }

        /// <summary>
        /// HttpWeb请求(SOAP1.2协议)
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="method">方法名</param>
        /// <returns></returns>
        public static string PostBySoap(string url, string xmlns, string method)
        {
            string postData = CreateSoapRequestXml(method, xmlns, null);
            string status;
            return WebRequest(RequestMethod.Post, url, true, null, postData, -1, out status);
        }

        /// <summary>
        /// HttpWeb请求(SOAP1.2协议)
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="method">方法名</param>
        /// <param name="htParams">参数</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static string PostBySoap(string url, string xmlns, string method, Hashtable htParams, int timeout)
        {
            string postData = CreateSoapRequestXml(method, xmlns, htParams);
            string status;
            return WebRequest(RequestMethod.Post, url, true, null, postData, timeout, out status);
        }

        /// <summary>
        /// HttpWeb请求(SOAP1.2协议)
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="method">方法名</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static string PostBySoap(string url, string xmlns, string method, int timeout)
        {
            string postData = CreateSoapRequestXml(method, xmlns, null);
            string status;
            return WebRequest(RequestMethod.Post, url, true, null, postData, timeout, out status);
        }

        #endregion

        #region SOAP Stream

        /// <summary>
        /// HttpWeb请求(SOAP1.2协议)
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="method">方法名</param>
        /// <param name="htParams">参数</param>
        /// <returns></returns>
        public static Stream PostBySoapStream(string url, string xmlns, string method, Hashtable htParams)
        {
            string postData = CreateSoapRequestXml(method, xmlns, htParams);
            string status;
            return WebRequestStream(RequestMethod.Post, url, true, null, postData, -1, out status);
        }

        /// <summary>
        /// HttpWeb请求(SOAP1.2协议)
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="method">方法名</param>
        /// <returns></returns>
        public static Stream PostBySoapStream(string url, string xmlns, string method)
        {
            string postData = CreateSoapRequestXml(method, xmlns, null);
            string status;
            return WebRequestStream(RequestMethod.Post, url, true, null, postData, -1, out status);
        }

        /// <summary>
        /// HttpWeb请求(SOAP1.2协议)
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="method">方法名</param>
        /// <param name="htParams">参数</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static Stream PostBySoapStream(string url, string xmlns, string method, Hashtable htParams, int timeout)
        {
            string postData = CreateSoapRequestXml(method, xmlns, htParams);
            string status;
            return WebRequestStream(RequestMethod.Post, url, true, null, postData, timeout, out status);
        }

        /// <summary>
        /// HttpWeb请求(SOAP1.2协议)
        /// </summary>
        /// <param name="url">网络地址</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="method">方法名</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        public static Stream PostBySoapStream(string url, string xmlns, string method, int timeout)
        {
            string postData = CreateSoapRequestXml(method, xmlns, null);
            string status;
            return WebRequestStream(RequestMethod.Post, url, true, null, postData, timeout, out status);
        }
        #endregion

        #region 私有方法

        /// <summary>
        /// HttpWeb请求
        /// </summary>
        /// <param name="requestMethod">请求方式</param>
        /// <param name="url">网络地址</param>
        /// <param name="isSoap">是否是SOAP协议</param>
        /// <param name="htParams">参数</param>
        /// <param name="postData">发送的数据</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        private static string WebRequest(RequestMethod requestMethod, string url, bool isSoap, Hashtable htParams, string postData, int timeout, out string status)
        {
            Stream stream = WebRequestStream(requestMethod, url, isSoap, htParams, postData, timeout, out status);
            string result = null;
            if (stream != null)
            {
                using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                {
                    result = reader.ReadToEnd();
                }
            }
            return result;
        }
        
        /// <summary>
        /// HttpWeb请求返回响应流
        /// </summary>
        /// <param name="requestMethod"></param>
        /// <param name="url"></param>
        /// <param name="isSoap"></param>
        /// <param name="htParams"></param>
        /// <param name="postData"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        private static Stream WebRequestStream(RequestMethod requestMethod, string url, bool isSoap, Hashtable htParams, string postData, int timeout, out string status)
        {
            if (String.IsNullOrEmpty(url.Trim()))
                throw new Exception("url参数不能为空!");
            //发送内容长度
            int contentLength = String.IsNullOrEmpty(postData) ? 0 : postData.Length;
            //GET方式 重构url
            if (requestMethod == RequestMethod.Get)
            {
                if (htParams != null && htParams.Count > 0)
                    url = ParametersToQueryString(url, htParams);
            }
            //创建HttpRequest
            HttpWebRequest request = CreateHttpWebRequest(url, requestMethod, isSoap);
            //设置超时时间
            if (timeout > 0)
                request.Timeout = timeout;
            else if (defaultTimeOut > 0)
                request.Timeout = defaultTimeOut;
            //发送数据
            if (requestMethod == RequestMethod.Post)
            {
                if (htParams != null && htParams.Count > 0)
                    postData = ParametersToStringData(htParams);

                if (!String.IsNullOrEmpty(postData))
                {
                    //request.ContentLength = postData.Length;
                    StreamWriter sw = new StreamWriter(request.GetRequestStream());
                    try
                    {
                        sw.Write(postData);
                    }
                    finally
                    {
                        sw.Close();
                        sw.Dispose();
                    }
                }
            }
            //获得请求结果
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK)
            {
                status = response.StatusDescription;
                return response.GetResponseStream();
            }
            //返回结果
            status = null;
            return null;
        }

        /// <summary>
        /// 将参数转化为URL连接
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="htParams">参数对</param>
        /// <returns></returns>
        private static string ParametersToQueryString(string url, Hashtable htParams)
        {
            StringBuilder sb = new StringBuilder();
            if (htParams != null && htParams.Count > 0)
            {
                foreach (DictionaryEntry de in htParams)
                    sb.Append("&" + de.Key.ToString() + "=" + HttpUtility.UrlEncode(de.Value.ToString()));
            }

            if (sb.Length > 0)
            {
                int queryIndex = url.IndexOf("?");
                if (queryIndex < 0)
                    sb.Remove(0, 1).Insert(0, "?");
                else if (queryIndex == url.Length - 1)
                    sb.Remove(0, 1);
                url += sb.ToString();
            }
            return url;
        }

        /// <summary>
        /// 将参数对转化为字符串数据
        /// </summary>
        /// <param name="htParams">参数对</param>
        /// <returns></returns>
        private static string ParametersToStringData(Hashtable htParams)
        {
            StringBuilder sb = new StringBuilder();
            if (htParams != null && htParams.Count > 0)
            {
                foreach (DictionaryEntry de in htParams)
                    sb.Append("&" + de.Key.ToString() + "=" + HttpUtility.UrlEncode(de.Value.ToString()));
                sb.Remove(0, 1);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 创建SOAP请求协议XML
        /// </summary>
        /// <param name="method">方法名</param>
        /// <param name="xmlns">命名空间</param>
        /// <param name="htParams">参数对</param>
        /// <returns></returns>
        private static string CreateSoapRequestXml(string method, string xmlns, Hashtable htParams)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            sb.AppendLine("<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">");
            sb.AppendLine("<soap12:Body>");
            sb.AppendLine("<" + method + " xmlns=\"" + xmlns + "\">");
            if (htParams != null && htParams.Count > 0)
            {
                foreach (DictionaryEntry de in htParams)
                {
                    string tagName = de.Key.ToString();
                    sb.AppendLine("<" + tagName + ">" + de.Value.ToString() + "</" + tagName + ">");
                }
            }
            sb.AppendLine("</" + method + ">");
            sb.AppendLine("</soap12:Body>");
            sb.AppendLine("</soap12:Envelope>");
            return sb.ToString();
        }

        /// <summary>
        /// 创建HttpRequest
        /// </summary>
        /// <param name="url">请求网络地址</param>
        /// <param name="requestMethod">请求方式</param>
        /// <param name="isSoap">是否是SOAP协议</param>
        /// <returns></returns>
        private static HttpWebRequest CreateHttpWebRequest(string url, RequestMethod requestMethod, bool isSoap)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            switch (requestMethod)
            {
                case RequestMethod.Post:
                    request.Method = "POST";
                    request.ContentType = isSoap ? "application/soap+xml; charset=utf-8" : "application/x-www-form-urlencoded";
                    break;
                case RequestMethod.Get:
                    request.Method = "GET";
                    request.ContentType = "application/x-www-form-urlencoded";
                    break;
            }
            return request;
        }

        #endregion

    }

    /// <summary>
    /// 请求方式
    /// </summary>
    public enum RequestMethod
    {
        /// <summary>
        /// POST
        /// </summary>
        Post,
        /// <summary>
        /// GET
        /// </summary>
        Get
    }

}
